package cjyyp.channel组件;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedInputStream;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

@Slf4j
public class channel常用api_客户端 {
    public static void main(String[] args) throws InterruptedException {
        NioEventLoopGroup group = new NioEventLoopGroup();
        //todo 带有Future 或者promise的一般都是异步方法
        ChannelFuture channelFuture = new Bootstrap()
                .group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new StringEncoder())
                                .addLast(new ChannelInboundHandlerAdapter(){
                                    @Override
                                    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                        ByteBuf buffer = (ByteBuf) msg;
                                        log.info("客户端接收数据[{}]",buffer.toString(StandardCharsets.UTF_8));
                                        super.channelRead(ctx, msg);
                                    }
                                });
                        ch.pipeline().addLast(new StringDecoder());
                    }
                })
                //todo 问题一：此方法为异步非阻塞。connect 方法是异步的，意味着不等连接建立，方法执行就返回了。因此 channelFuture 对象中不能【立刻】获得到正确的 Channel 对象
                //真的连接的是nio线程
                .connect("127.0.0.1", 8080);
//        channelFuture.sync();//todo 方法1：所以这一步是等待channel成功连接
//        Channel channel = channelFuture.channel();
//        channel.write("cjyylkj");
//        channel.flush();
//        channel.close();
        //todo 还有一种方法2：通过回调函数
        Channel channel = channelFuture.channel();
        channelFuture.addListener(new ChannelFutureListener() {
            //channelFuture建立好连接后，nio线程调用此回调函数
            @Override
            public void operationComplete(ChannelFuture channelFuture)  {
                new Thread(()->{
                    Scanner scanner=new Scanner(new BufferedInputStream(System.in));
                    while (true){
                        String line = scanner.nextLine();
                        if ("stop".equals(line)){
                            channel.close();
                            break;
                        }else {
                            log.info(line);
                            channel.writeAndFlush(line);
                        }
                    }
                },"客户端手动输入线程").start();
            }
        });
        ChannelFuture closeFuture = channel.closeFuture();
        closeFuture.addListener(new ChannelFutureListener() {
            //channel关闭后，nio线程调用此回调方法
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                log.info("channel关闭后的操作。。。");
                group.shutdownGracefully();//这一步才能完全关闭客户端
            }
        });
    }
}
